package com.zhaungjie.base.utils;

import org.springframework.web.method.HandlerMethod;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 反射的 Utils 函数集合
 * 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
 */
public class ReflectionUtils {


    /**
     * 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
     *
     * @param object
     * @param fieldName
     * @return
     */
    public static Object getFieldValue(Object object, String fieldName) {
        Field field = getDeclaredField(object.getClass(), fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
        }

        makeAccessible(field);

        Object result = null;

        try {
            result = field.get(object);
        } catch (IllegalAccessException e) {
        }

        return result;
    }


    /**
     * 获取对象的指定类型的值
     *
     * @param obj
     * @param clazz
     * @param <T>
     * @return
     * @throws IllegalAccessException
     */
    public static <T> T getFieldValue(Object obj, Class<T> clazz) {
        T foundValue = null;
        Field[] fields = getDeclaredFields(obj.getClass(), clazz, true);
        if (fields.length > 0) {
            // 如果有多个，使用“最近”的
            Field field = fields[0];
            // 确保字段可访问
            field.setAccessible(true);
            // 检查字段的类型
            if (field.getType().equals(clazz)) {
                try {
                    foundValue = (T) field.get(obj);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
        }
        return foundValue;
    }


    /**
     * 获取类的所有属性
     * @param clazz          要搜索的起点类class
     * @param isSearchUpward 是否向上搜索
     * @return {@link Map}<{@link Field},{@link String}>
     */
    public static Map<Field,String> getDeclaredFields(Class<?> clazz, boolean isSearchUpward) {
        List<Field> fieldList = new ArrayList<>();
        for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
            Field[] fields = superClass.getDeclaredFields();
            if (!isSearchUpward) break;
            fieldList.addAll(Arrays.asList(fields));
        }
        return fieldList.stream().collect(Collectors.toMap(field->field, Field::getName));
    }

    /**
     * 获取类指定类型的属性Field对象
     *
     * @param clazz          要搜索的起点类class
     * @param tClass         目标属性类class
     * @param isSearchUpward 是否向上搜索
     * @return {@link Field[]}
     */
    public static Field[] getDeclaredFields(Class<?> clazz, Class<?> tClass, boolean isSearchUpward) {
        List<Field> fieldList = new ArrayList<>();
        for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
            Field[] fields = superClass.getDeclaredFields();
            if (!isSearchUpward) break;
            for (Field field : fields) {
                if (field.getType().equals(tClass)) {
                    fieldList.add(field);
                }
            }
        }
        Field[] result = new Field[fieldList.size()];
        return fieldList.toArray(result);
    }

    /**
     * 获从类Class开始获取最近满足指定属性名的Field对象
     *
     * @param clazz
     * @param fieldName
     * @return
     * @throws NoSuchFieldException
     */
    public static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            Class<?> superclass = clazz.getSuperclass();
            if (superclass == null) {
                // the field could not be found
                throw e;
            } else {
                // try to find the field in the superclass
                return getField(superclass, fieldName);
            }
        }
    }

    /**
     * 根据属性class将值设置到对象里
     * @param object 目标对象
     * @param targetFieldClass 目标属性class
     * @param fieldValue 目标属性新值
     */
    public static void setFieldValue(Object object,Class<?> targetFieldClass,Object fieldValue) {
        Field[] fields = getDeclaredFields(object.getClass(),targetFieldClass,true);
        for (Field currentField : fields) {
            setFieldValue(object,currentField.getName(),fieldValue);
        }
    }
    /**
     * 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
     *
     * @param object
     * @param fieldName
     * @param value
     */
    public static void setFieldValue(Object object, String fieldName, Object value) {
        Field field = getDeclaredField(object.getClass(), fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
        }

        makeAccessible(field);

        try {
            field.set(object, value);
        } catch (IllegalAccessException e) {
        }
    }


    /**
     * 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型
     * 如: public EmployeeDao extends BaseDao<Employee, String>
     *
     * @param clazz
     * @param index
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Class getSuperClassGenricType(Class clazz, int index) {
        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            return Object.class;
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            return Object.class;
        }

        if (!(params[index] instanceof Class)) {
            return Object.class;
        }

        return (Class) params[index];
    }

    /**
     * 通过反射, 获得 Class 定义中声明的父类的泛型参数类型
     * 如: public EmployeeDao extends BaseDao<Employee, String>
     *
     * @param <T>
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> getSuperGenericType(Class clazz) {
        return getSuperClassGenricType(clazz, 0);
    }

    /**
     * 循环向上转型, 获取对象的 DeclaredMethod
     *
     * @param object
     * @param methodName
     * @param parameterTypes
     * @return
     */
    public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes) {

        for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredMethod(methodName, parameterTypes);
            } catch (NoSuchMethodException e) {
                //Method 不在当前类定义, 继续向上转型
            }
        }

        return null;
    }

    /**
     * 使 filed 变为可访问
     *
     * @param field
     */
    public static void makeAccessible(Field field) {
        if (!Modifier.isPublic(field.getModifiers())) {
            field.setAccessible(true);
        }
    }

    /**
     * 循环向上转型, 获取对象的 DeclaredField
     *
     * @param clazz
     * @param filedName
     * @return
     */
    public static Field getDeclaredField(Class<?> clazz, String filedName) {
        for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(filedName);
            } catch (NoSuchFieldException e) {
                //Field 不在当前类定义, 继续向上转型
            }
        }
        return null;
    }

    /**
     * 直接调用对象方法, 而忽略修饰符(private, protected)
     *
     * @param object
     * @param methodName
     * @param parameterTypes
     * @param parameters
     * @return
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     */
    public static Object invokeMethod(Object object, String methodName, Class<?>[] parameterTypes,
                                      Object[] parameters) throws InvocationTargetException {

        Method method = getDeclaredMethod(object, methodName, parameterTypes);

        if (method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
        }

        method.setAccessible(true);

        try {
            return method.invoke(object, parameters);
        } catch (IllegalAccessException e) {
        }

        return null;
    }


    /**
     * 获取对象属性
     *
     * @param obj obj
     * @return {@link Map}<{@link String}, {@link Object}>
     */
    public static Map<String, Object> getObjectProperties(Object obj) {
        Map<String, Object> propertiesMap = new HashMap<>();

        // 获取对象的类
        Class<?> clazz = obj.getClass();

        // 获取对象的所有属性（包括继承的属性）
        List<Field> fieldList = new ArrayList<>();

        Class tempClass = obj.getClass();
        while (tempClass != null) {
            //当父类为null的时候说明到达了最上层的父类(Object类)
            fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
            //得到父类,然后赋给自己
            tempClass = tempClass.getSuperclass();
        }

        // 遍历属性并将其放入Map
        for (Field field : fieldList) {
            field.setAccessible(true);  // 设置属性的可访问性（私有属性也可以访问）
            String propertyName = field.getName();
            try {
                Object propertyValue = field.get(obj);
                propertiesMap.put(propertyName, propertyValue);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return propertiesMap;
    }


    /**
     * 创建实例
     *
     * @param clazz clazz
     * @return {@link T}
     */
    public static <T> T createInstance(Class<T> clazz) {
        try {
            Constructor<T> declaredConstructor = clazz.getDeclaredConstructor();
            declaredConstructor.setAccessible(true);
            T instance = declaredConstructor.newInstance();
            return instance;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 从类中获取注解
     *
     * @param clazz           拍手
     * @param annotationClass 注释类
     * @return {@link T}
     */
    public static <T extends Annotation> T getAnnotationFromClass(Class<?> clazz, Class<T> annotationClass) {
        if (clazz == null) throw new RuntimeException("无法从类中获取注解，因为传入的class为空");
        return clazz.getAnnotation(annotationClass);
    }

    /**
     * 从实例获取注解
     *
     * @param object          对象
     * @param annotationClass 注释类
     * @return {@link T}
     */
    public static <T extends Annotation> T getAnnotationFromInstance(Object object, Class<T> annotationClass) {
        if (object == null) throw new RuntimeException("无法从类中获取注解，因为传入的instance为空");
        return getAnnotationFromClass(object.getClass(), annotationClass);
    }

    /**
     * 获取注释
     *
     * @param handlerMethod   handler方法
     * @param annotationClass 注释类
     * @return {@link T}
     */
    public static <T extends Annotation> T getAnnotationFromMethod(HandlerMethod handlerMethod, Class<T> annotationClass, boolean isOnNullFromType) {
        if (handlerMethod == null) return null;
        T targetAnnotation = handlerMethod.getMethodAnnotation(annotationClass);
        if (targetAnnotation == null && isOnNullFromType) {
            // 从类上获取注解
            return getAnnotationFromClass(handlerMethod.getBeanType(), annotationClass);
        }
        return targetAnnotation;
    }

    public static <T extends Annotation> Boolean isHasAnnotation(HandlerMethod handlerMethod, Class<T> annotationClass, boolean isOnNullFromType) {
        return getAnnotationFromMethod(handlerMethod, annotationClass, isOnNullFromType) != null;
    }

    /**
     * 在类中查找带指定注解方法
     *
     * @param clazz           拍手
     * @param annotationClass 注释类
     * @return {@link List}<{@link Method}>
     */
    public static <T extends Annotation> List<Method> findAnnotatedMethodsInClass(Class<?> clazz, Class<T> annotationClass) {
        Method[] methods = clazz.getDeclaredMethods(); // 获取所有的方法，包括私有的
        if (methods == null || methods.length == 0) return new ArrayList<>();
        return Arrays.stream(methods).filter(method -> method.isAnnotationPresent(annotationClass)).collect(Collectors.toList());
    }

    /**
     * 尝试从一个Object中获取指定属性
     *
     * @param obj       对象
     * @param fieldName 字段名称
     * @return {@link Object}
     */
    public static Object getFieldValueFromObject(Object obj, String fieldName) {
        if (obj == null || fieldName == null || fieldName.isEmpty()) {
            return null;
        }
        try {
            Field requestField = obj.getClass().getDeclaredField(fieldName);
            // 设置访问权限（如果request是私有属性）
            requestField.setAccessible(true);
            // 获取属性值
            return requestField.get(obj);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取一个类中所有方法
     *
     * @param clazz 拍手
     * @return {@link List}<{@link Method}>
     */
    public static List<Method> getAllMethods(Class<?> clazz) {
        List<Method> methods = new ArrayList<>();
        while (clazz != null) {
            for (Method declaredMethod : clazz.getDeclaredMethods()) {
                methods.add(declaredMethod);
            }
            clazz = clazz.getSuperclass();
        }
        return methods;
    }

    /**
     * 按注释筛选方法
     *
     * @param clazz           拍手
     * @param annotationClass 注释类
     * @return {@link List}<{@link Method}>
     */
    public static List<Method> filterMethodsByAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass) {
        List<Method> allMethods = getAllMethods(clazz);
        return allMethods.stream().filter(method -> method.isAnnotationPresent(annotationClass)).collect(Collectors.toList());
    }

    /**
     * 根据指定注解获取标注了该方法参数下标
     *
     * @param method
     * @param sendClass
     * @return
     */
    public static int getOneParamIndexByAnnotation(Method method, Class<? extends Annotation> sendClass) {
        try {
            Parameter[] parameters = method.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                if (parameters[i].isAnnotationPresent(sendClass)) {
                    return i;
                }
            }
        } catch (Exception e) {
        }
        return -1;
    }


    @FunctionalInterface
    public interface ParameterValueProviderByClass<T> {
        T process(Annotation[] annotations, Class<T> clazz);
    }

    @FunctionalInterface
    public interface ParameterValueProviderByAnnotation<T extends Annotation> {
        Object process(T annotations, Class<?> clazz);
    }

    /**
     * 生成方法参数值
     *
     * @param method                  方法
     * @param providerByClassMap      按类映射提供程序
     * @param providerByAnnotationMap 按注释映射提供程序
     * @return {@link Object[]}
     */
    public static Object[] genMethodParamValues(Method method, Map<Class, ParameterValueProviderByClass> providerByClassMap, Map<Class<? extends Annotation>, ParameterValueProviderByAnnotation> providerByAnnotationMap) {
        if (method == null) return null;
        // 获取所有参数类型
        Class<?>[] parameterTypes = method.getParameterTypes();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        Object[] parametersValue = new Object[parameterTypes.length];
        // 循环所有参数，通过反射创建实例（这里假设都有默认构造函数）
        for (int i = 0; i < parameterTypes.length; i++) {
            Annotation[] parameterAnnotation = parameterAnnotations[i];
            Class<?> parameterType = parameterTypes[i];
            ParameterValueProviderByClass parameterValueProviderByClass = providerByClassMap.get(parameterType);
            if (parameterValueProviderByClass != null) {
                Object process = parameterValueProviderByClass.process(parameterAnnotation, parameterType);
                parametersValue[i] = process;
            }
            if (parameterAnnotation != null && parameterAnnotation.length > 0 && providerByAnnotationMap != null && !providerByAnnotationMap.isEmpty()) {
                for (Annotation annotation : parameterAnnotation) {
                    ParameterValueProviderByAnnotation parameterValueProviderByAnnotation = providerByAnnotationMap.get(annotation.annotationType());
                    if (parameterValueProviderByAnnotation == null) continue;
                    parametersValue[i] = parameterValueProviderByAnnotation.process(annotation, parameterType);
                }
            }
        }
        return parametersValue;
    }

    /**
     * 获取注释
     *
     * @param handlerMethod   handler方法
     * @param annotationClass 注释类
     * @return {@link T}
     */
    public static <T extends Annotation> T getAnnotation(HandlerMethod handlerMethod, Class<T> annotationClass, boolean isOnNullFromType) {
        if (handlerMethod == null) return null;
        T targetAnnotation = handlerMethod.getMethodAnnotation(annotationClass);
        if (targetAnnotation == null && isOnNullFromType) {
            // 从类上获取注解
            targetAnnotation = handlerMethod.getBeanType().getAnnotation(annotationClass);
        }
        return targetAnnotation;
    }


    /**
     * 从字段获取指定注解
     *
     * @param field           领域
     * @param annotationClass 注释类
     * @return {@link T}
     */
    public static <T extends Annotation> T getAnnotation(Field field, Class<T> annotationClass) {
        if (field.isAnnotationPresent(annotationClass)) {
            return field.getAnnotation(annotationClass);
        }
        return null;
    }

}